import {
  Controller,
  UseGuards,
  UploadedFile,
  BadRequestException,
} from '@nestjs/common';
import {
  Crud,
  CrudController,
  Override,
  ParsedRequest,
  ParsedBody,
  CrudRequest,
} from '@nestjsx/crud';
import { ApiTags, ApiBearerAuth, ApiConsumes } from '@nestjs/swagger';
import { UsersService } from '../services/users.service';
import { User } from '../entities/user.entity';
import { UserRole, FileStoragePath } from '@/enum';
import { Roles } from '@/decorators/roles.decorator';
import { AuthGuard, RolesGuard, SelfOnlyGuard } from '@/guards';
import { FileUtils } from '@/utils';
import { RequestDtoRelationTransformer } from '@/interfaces';
import {
  Artist,
  Song,
  Album,
  PlayList,
  ArtistEdition,
  AlbumEdition,
  Score,
  Track,
  Post,
} from '@/modules/resources';
import { deserializeArray } from 'class-transformer';

@Crud({
  model: {
    type: User,
  },
  query: {
    exclude: ['password'],
    limit: 25,
    maxLimit: 100,
    join: {
      followedArtists: {},
      favSongs: {},
      favAlbums: {},
      playLists: {},
      editedArtistEditions: {},
      editedAlbumEditions: {},
      uploadedScores: {},
      uploadedTracks: {},
      posts: {},
    },
  },
  routes: {
    exclude: ['createManyBase', 'deleteOneBase'],
    updateOneBase: {
      interceptors: [
        FileUtils.singleFileUploader(
          'avatar',
          ['image'],
          FileStoragePath.UPLOAD_IMAGES,
        ),
      ],
    },
    replaceOneBase: {
      // decorators: [
      //   UseGuards(AuthGuard, RolesGuard),
      //   Roles(UserRole.ADMIN),
      //   ApiBearerAuth(),
      // ],
      interceptors: [
        FileUtils.singleFileUploader(
          'avatar',
          ['image'],
          FileStoragePath.UPLOAD_IMAGES,
        ),
      ],
    },
    // deleteOneBase: {
    //   decorators: [
    //     UseGuards(AuthGuard, RolesGuard),
    //     Roles(UserRole.ADMIN),
    //     ApiBearerAuth(),
    //   ],
    // },
    createOneBase: {
      // decorators: [
      //   UseGuards(AuthGuard, RolesGuard),
      //   Roles(UserRole.ADMIN),
      //   ApiBearerAuth(),
      // ],
      interceptors: [
        FileUtils.singleFileUploader(
          'avatar',
          ['image'],
          FileStoragePath.UPLOAD_IMAGES,
        ),
      ],
    },
  },
})
@ApiTags('users')
@Controller('users')
// eslint-disable-next-line prettier/prettier
export class UsersController implements CrudController<User>, RequestDtoRelationTransformer<User> {
  constructor(public service: UsersService) {}

  get base(): CrudController<User> {
    return this;
  }

  dtoRelationTransform(dto: User) {
    try {
      if (typeof dto.followedArtists === 'string') {
        dto.followedArtists = deserializeArray(Artist, dto.followedArtists);
      }
      if (typeof dto.favSongs === 'string') {
        dto.favSongs = deserializeArray(Song, dto.favSongs);
      }
      if (typeof dto.favAlbums === 'string') {
        dto.favAlbums = deserializeArray(Album, dto.favAlbums);
      }
      if (typeof dto.playLists === 'string') {
        dto.playLists = deserializeArray(PlayList, dto.playLists);
      }
      if (typeof dto.editedArtistEditions === 'string') {
        dto.editedArtistEditions = deserializeArray(
          ArtistEdition,
          dto.editedArtistEditions,
        );
      }
      if (typeof dto.editedAlbumEditions === 'string') {
        dto.editedAlbumEditions = deserializeArray(
          AlbumEdition,
          dto.editedAlbumEditions,
        );
      }
      if (typeof dto.uploadedScores === 'string') {
        dto.uploadedScores = deserializeArray(Score, dto.uploadedScores);
      }
      if (typeof dto.uploadedTracks === 'string') {
        dto.uploadedTracks = deserializeArray(Track, dto.uploadedTracks);
      }
      if (typeof dto.posts === 'string') {
        dto.posts = deserializeArray(Post, dto.posts);
      }
    } catch (e) {
      if (e instanceof SyntaxError) {
        throw new BadRequestException(e.message, e.name);
      }
      throw new BadRequestException();
    }

    return dto;
  }

  @UseGuards(AuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  createOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: User,
    @UploadedFile() avatar?: Express.Multer.File,
  ) {
    dto = this.dtoRelationTransform(dto);
    if (avatar) {
      dto.avatar = avatar.path;
    }
    return this.base.createOneBase(req, dto);
  }

  @UseGuards(AuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  updateOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: User,
    @UploadedFile() avatar?: Express.Multer.File,
  ) {
    dto = this.dtoRelationTransform(dto);
    if (avatar) {
      dto.avatar = avatar.path;
    }
    return this.base.createOneBase(req, dto);
  }

  @UseGuards(AuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  replaceOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: User,
    @UploadedFile() avatar?: Express.Multer.File,
  ) {
    dto = this.dtoRelationTransform(dto);
    if (avatar) {
      dto.avatar = avatar.path;
    }
    return this.base.createOneBase(req, dto);
  }
}
